package spring.boot.server.server;

import com.alibaba.fastjson.JSON;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelId;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import spring.boot.server.common.NettyServerConstant;

import java.util.HashMap;
import java.util.Map;

/**
 * 服务端 Channel 实现类，提供对客户端 Channel 建立连接、断开连接、异常时的处理
 */
@Slf4j
@Component
@ChannelHandler.Sharable
public class NettyServerHandler extends ChannelInboundHandlerAdapter {

    @Autowired
    private NettyChannelManager channelManager;

    /**
     * 将channel添加到channel管理器中
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        channelManager.add(ctx.channel());
    }

    /**
     * 从channel管理器中移除channel
     */
    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) {
        channelManager.remove(ctx.channel());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) {
        log.error("连接[{}]发生异常, errorMsg=[{}]", ctx.channel().id(), e.getMessage(), e);
        // 断开连接
        ctx.channel().close();
    }


    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            log.info("Netty服务端心跳检测,已经5秒未收到客户端[{}]的消息了！", ctx.channel().id());
            IdleStateEvent event = (IdleStateEvent) evt;
            if (event.state() == IdleState.READER_IDLE) {
                Integer num = NettyServerConstant.HEART_BEAT_MAP.get(ctx.channel().id());
                if (num == null) {
                    num = 0;
                }
                num++;
                NettyServerConstant.HEART_BEAT_MAP.put(ctx.channel().id(), num);
                if (num > 2) {
                    log.info("Netty服务端心跳检测,关闭这个不活跃通道[{}]！", ctx.channel().id());
                    ctx.channel().close();
                }
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        NettyServerConstant.HEART_BEAT_MAP.put(ctx.channel().id(), 0);
        log.info("客户端[{}]消息=[{}]", ctx.channel().id(), JSON.toJSONString(msg));
    }
}
